import json
import time
import cv2
import requests
import numpy as np
import base64
from kafka import KafkaConsumer, KafkaClient
from kafka.structs import TopicPartition
import YITUYDN
import mongo_
import redis_
import faceToolsV2
import dnnDetect
import faceTools

with open('../config.py', 'r') as f:
    exec(f.read())

feature1_S = bytearray([123, 34])
feature1_E = bytearray([34, 125])
feature2_S = bytearray([123, 10, 32, 32, 32, 34])
feature2_E = bytearray([34, 10, 125])


def get_image(img_dic):
    # 修改为获取自己的url
    # image_url = ''
    image_url = yituydn.getImgUrl(img_dic['face_image_uri'])

    try:
        file = requests.get(image_url)
    except Exception as e:
        print(e)
        return {}
    return file.content


def img_to_base64(bs):
    base64_data = base64.b64encode(bs)
    s = base64_data.decode()
    return s


def bsToCv(bs):
    image_ = cv2.imdecode(np.frombuffer(bs, np.uint8), 1)
    return image_


def get_f(imgbase64, ovn_f):
    # 获取特征值
    # return ovn_f
    url = 'http://192.168.1.40:5000/getbigf'
    data = {
        'base64': imgbase64
    }
    try:
        r = requests.post(url, json.dumps(data))
        # print(r.text)

        res = json.loads(r.text)
        return res['f']
    except:
        time.sleep(2)
        return None


def ovo(a_base64_f, b_base64_f):
    # yituovo
    # # hit_image_yitu_171_feature_base64 = img_hit['yitu_171_feature_base64']
    # # ovo_rtn = yituydn.ovo(face_yitu_171_feature_base64, hit_image_yitu_171_feature_base64)
    # # if ovo_rtn['rtn'] == 0:
    # #     new_similarity = ovo_rtn['similarity']
    # # else:
    # #     new_similarity = -1
    if a_base64_f == '' or b_base64_f == '':
        return -1

    # 1.40 ovo
    url = 'http://192.168.1.40:5000/faceoof'
    data = {
        "a": a_base64_f,
        "b": b_base64_f
    }
    try:
        r = requests.post(url, json.dumps(data))
        # print(r.text)

        res = json.loads(r.text)
        return res['similarity']
    except:
        time.sleep(2)
        return -1


def ovo_main(f_ovn_f, hit_ovn_f, f_ovo_f, hit_ovo_f, flag=True):
    if flag:
        return ovo(f_ovo_f, hit_ovo_f)

    if not flag:
        return ovo(f_ovn_f, hit_ovn_f)


def detect_front(detectFacev2, detectCount, detectFaceV1):
    if detectFaceV1['detectFace'] == 1:
        if detectFacev2 != 1 or detectCount >= 2 or abs(detectFaceV1['x']) > 40 or abs(
                detectFaceV1['y']) > 40 or abs(detectFaceV1['z']) > 40:
            return False
        else:
            return True
    else:
        return False


def insert_redis_mongo(images, data_dic):
    detectFacev2 = int(faceToolsV2.detect_(images))
    detectCount = dnnDetect.detect_(images)
    detectFaceV1 = faceTools.detect_(images)
    # print(detectFacev2)
    is_front = detect_front(detectFacev2, detectCount, detectFaceV1)
    # 入db15
    db15_data = {
        'camera_id': data_dic['camera_id'],
        'face_image_id': data_dic['face_image_id'],
        'face_image_uri': data_dic['face_image_uri'],
        'picture_uri': data_dic['picture_uri'],
        'timestamp': data_dic['timestamp'],
        '_id': data_dic['face_image_id'],
        'ip': data_dic['ip'],
        'detectFacev2': detectFacev2,
        'detectCount': detectCount,
        'ovn_f': data_dic['ovn_f'],
        # 'ovo_f': data_dic['f'],
        'is_front': is_front
    }
    db15_data.update(detectFaceV1)
    # 入redis
    for key in db15_data:
        redis_.insert(data_dic['face_image_id'], key, str(db15_data[key]))
    # 入mongo
    mongo_.insert_cap(db15_data)
    return is_front


def get_ovncam_dic(similarity, hitface_id, camera_id, new_similarity, is_front):
    hit_dic = {
        'similarity': similarity,
        'hit_face_image_id': hitface_id,
        'camera_id': camera_id,
        'ovo_similarity': new_similarity,
        'is_front': is_front
    }
    return hit_dic


def get_redis_f(img_hit):
    ovo_key_has = redis_.has_h_key(img_hit['face_image_id'], 'ovo_f')

    if ovo_key_has:
        hit_f_base64 = redis_.RDB_getFace(img_hit['face_image_id'])['ovo_f']

    if not ovo_key_has:
        bss = get_image(img_hit)
        hit_f_base64 = get_f(img_to_base64(bss), img_hit['ovn_f'])
        redis_.insert_key(img_hit['face_image_id'], 'ovo_f', hit_f_base64)

    return hit_f_base64


#
def logic(face_img, cam_ovn, card_ovn):
    # face_img: {'face_image_id': , 'timestamp': , 'ip': , 'ovn_f': , 'face_image_uri': , 'camera_id': , 'picture_uri': , 'ovn_f': ,}
    # cam_ovn:[{'face_image_id': , 'camera_id': , 'similarity': , 'face_image_uri': , 'picture_uri': ,  'timestamp': , 'ip': , 'ovn_f': ,}]
    # card_ovn:[{'face_image_id': , 'repository_id': , 'similarity': , 'face_image_uri': , 'picture_uri': ,
    # 'name': , 'person_id': , 'timestamp': , 'ip': , 'ovn_f'}]

    face_img_id = face_img['face_image_id']
    timestamp = face_img['timestamp']

    ebn_result = []

    face_has = redis_.haskey(face_img_id)

    bs = get_image(face_img)
    if len(bs) < 2000:
        return

    face_image = bsToCv(bs)

    if face_image is None:
        return

    if not face_has:
        # f_base64 = get_f(img_to_base64(bs), face_img['ovn_f'])
        # face_img['f'] = f_base64
        face_front = insert_redis_mongo(face_image, face_img)

    if face_has:
        redis_face_img = redis_.RDB_getFace(face_img_id)
        # f_base64 = redis_face_img['ovo_f']
        face_front = redis_face_img['is_front']

    # 第一遍循环统计数据
    hit_face_acvs_dic = {}
    face_front_dic = {}
    acvs_list = []

    for img_hit in cam_ovn:
        hit_face_id = img_hit['face_image_id']

        if hit_face_id == face_img_id:
            continue

        hit_face_has = redis_.haskey(hit_face_id)

        bs1 = get_image(img_hit)
        if len(bs1) < 2000:
            continue

        hit_image = bsToCv(bs1)
        if hit_image is None:
            continue

        if not hit_face_has:
            # hit_base64 = get_f(img_to_base64(bs1), img_hit['ovn_f'])
            # img_hit['f'] = hit_base64
            insert_redis_mongo(hit_image, img_hit)

        if face_front:
            hit_face_front = redis_.RDB_getFace(hit_face_id)['is_front']
            face_front_dic[hit_face_id] = hit_face_front
            if hit_face_front:
                hit_face_acvs_dic[hit_face_id] = []
                redis_.RDB_getfaceacvsall(hit_face_id, hit_face_acvs_dic, acvs_list, start=0, end=-1)

    # 统计
    if not face_front:
        for img_hit in cam_ovn:
            similarity = img_hit['similarity']
            camera_id = img_hit['camera_id']
            hitface_id = img_hit['face_image_id']
            if hitface_id == face_img_id:
                continue

            hitface_front = redis_.RDB_getFace(hitface_id)['is_front']
            hit_dic = get_ovncam_dic(similarity, hitface_id, camera_id, 0, hitface_front)
            ebn_result.append(hit_dic)

    if face_front:
        # 第二遍插入数据
        for img_hit in cam_ovn:
            acvs_tuple_list = []
            count_list = []
            similarity = img_hit['similarity']
            camera_id = img_hit['camera_id']
            hitface_id = img_hit['face_image_id']
            if hitface_id == face_img_id:
                continue

            # 97 98侧脸
            if hitface_id not in hit_face_acvs_dic:
                # hitface_front = False
                hit_dic = {
                    'similarity': similarity,
                    'hit_face_image_id': hitface_id,
                    'camera_id': camera_id,
                    'is_front': False
                }
                ebn_result.append(hit_dic)

            else:
                hit_acvs_list = hit_face_acvs_dic[img_hit['face_image_id']]
                # 正脸没有档
                if len(hit_acvs_list) == 0:

                    # ovo获取base64之前判断 db15 是否含有这个face_id
                    # 添加 查询和获取 ovo_f

                    f_base64 = get_redis_f(face_img)
                    hit_f_base64 = get_redis_f(img_hit)
                    new_similarity = ovo_main(face_img['ovn_f'], img_hit['ovn_f'], f_base64, hit_f_base64)

                    # new_similarity = ovo(f_base64, hit_f_base64)   ############ 双向接口

                    hit_dic = get_ovncam_dic(similarity, hitface_id, camera_id, new_similarity,
                                             face_front_dic[hitface_id])

                    hit_dic['acvs_id'] = acvs_tuple_list
                    ebn_result.append(hit_dic)
                # 正脸有档
                else:
                    for acvs_id in hit_acvs_list:
                        acvs_tuple_list.append((acvs_id, acvs_list.count(acvs_id)))
                        count_list.append(acvs_list.count(acvs_id))
                    count_max = max(count_list)
                    if count_max < 2:
                        # hit_f_base64 = redis_.RDB_getFace(img_hit['face_image_id'])['ovo_f']

                        f_base64 = get_redis_f(face_img)
                        hit_f_base64 = get_redis_f(img_hit)

                        new_similarity = ovo_main(face_img['ovn_f'], img_hit['ovn_f'], f_base64, hit_f_base64)

                        hit_dic = get_ovncam_dic(similarity, hitface_id, camera_id, new_similarity,
                                                 face_front_dic[hitface_id])
                        hit_dic['acvs_id'] = acvs_tuple_list
                        ebn_result.append(hit_dic)
                    else:
                        hit_dic = get_ovncam_dic(similarity, hitface_id, camera_id, count_max * 100,
                                                 face_front_dic[hitface_id])
                        hit_dic['acvs_id'] = acvs_tuple_list
                        ebn_result.append(hit_dic)

    for card_hit_img in card_ovn:
        hit_card_id = card_hit_img['face_image_id']
        hit_card_has = redis_.haskey(hit_card_id)

        bs2 = get_image(card_hit_img)
        if len(bs2) < 2000:
            continue
        hitcard_image = bsToCv(bs2)

        if hitcard_image is None:
            continue

        if not hit_card_has:
            data15_card = {
                'repository_id': card_hit_img['repository_id'],
                'face_image_id': card_hit_img['face_image_id'],
                'face_image_uri': card_hit_img['face_image_uri'],
                'picture_uri': card_hit_img['picture_uri'],
                'timestamp': card_hit_img['timestamp'],
                '_id': card_hit_img['face_image_id'],
                'ip': card_hit_img['ip'],
                'name': card_hit_img['name'],
                'person_id': card_hit_img['person_id'],
                'ovn_f': card_hit_img['ovn_f'],
            }

            # 入redis
            for card_key in data15_card:
                redis_.insert(hit_card_id, card_key, data15_card[card_key])
            # 入mongo
            mongo_.insert_cap(data15_card)

        similarity = card_hit_img['similarity']
        repository_id = card_hit_img['repository_id']
        card_hit_dic = {
            'similarity': similarity,
            'hit_face_image_id': hit_card_id,
            'hit_repository_id': repository_id
        }

        ebn_result.append(card_hit_dic)

    ebn_result = sorted(ebn_result, key=lambda x: x['similarity'], reverse=True)

    ebndata = {
        "face_image_id": face_img_id,
        "result": ebn_result,
        "is_front": face_front,
        "timestamp": timestamp
    }
    # 插入ebn结果
    redis_.insertebn(json.dumps(ebndata))


def real(data):
    start = 0
    end = 0
    # find {
    if start == 0:
        start = data.find(feature2_S)
    if start == 0:
        start = data.find(feature1_S)
    # find }
    if end == 0:
        end = data.rfind(feature2_E)
    if end == 0:
        end = data.rfind(feature1_E)
    return data[start:end + len(feature2_E) + 1]


while True:
    try:
        topic1 = 'track_meta'
        topicPartition = TopicPartition(topic=topic1, partition=0)
        consumer = KafkaConsumer(topic1, group_id=kafkainfo['group_id'],
                                 bootstrap_servers=kafkainfo['bootstrap_servers'], max_poll_records=50)
        print(consumer.topics())

        yituydn = YITUYDN.YITUYDN(yituinfo['ip'], yituinfo['port'], yituinfo['username'],
                                  yituinfo['password'])

        H_IP = yituydn.ip
        cluster_id = yituydn.getCluster_id()

        camera_list = yituydn.camera_list(yituydn.getcamera())
        repository_list = yituydn.repository_list(yituydn.getrepository())
        break
    except Exception as e:
        print(e)
        time.sleep(10)

# consumer.seek_to_beginning()
# consumer.seek_to_end(topicPartition)
time_interval = 10
now_time = int(time.time())
while True:
    print('run1 empty', time.time())
    try:
        messages = consumer.poll()
        if messages == {}:
            time.sleep(1)
            continue
        messages = messages[topicPartition]
        for message in messages:
            # print(message.topic, message.offset, time.time())
            data = bytearray(message.value)
            data = real(data)
            data = json.loads(data)
            if not data['track_finished']:
                continue
            print('run1 runing', time.time())

            if int(time.time()) - now_time >= time_interval:
                now_time = int(time.time())
                camera_list = yituydn.camera_list(yituydn.getcamera())
                repository_list = yituydn.repository_list(yituydn.getrepository())
            # print(data)

            data['camera_id'] = str(data['camera_id']) + '@' + cluster_id
            data['face_image_id'] = str(data['face_image_id']) + '@' + cluster_id
            data['face_image_uri'] = str(data['face_image_uri']) + '@' + cluster_id
            data['picture_uri'] = str(data['picture_uri']) + '@' + cluster_id

            data['ip'] = H_IP
            data['ovn_f'] = data['yitu_171_feature_base64']
            face_img_id = data['face_image_id']

            bs = get_image(data)
            if len(bs) < 2000:
                continue
            image = bsToCv(bs)
            if image is None:
                continue
            image_content_base64 = base64.b64encode(bs).decode()
            cam_ovn = yituydn.ovn(camera_list, None, image_content_base64, guidanginfo['face_similarity'], [], [],
                                  guidanginfo['face_limit'])
            card_ovn = yituydn.ovn(None, repository_list, image_content_base64, guidanginfo['card_similarity'], [], [],
                                   guidanginfo['card_limit'])

            if cam_ovn['rtn'] == 0:
                for hit_img in cam_ovn['results']:
                    hit_img['ip'] = H_IP
                    hit_img['ovn_f'] = hit_img['yitu_171_feature_base64']

            else:
                camera_list = yituydn.camera_list(yituydn.getcamera())
                repository_list = yituydn.repository_list(yituydn.getrepository())
                continue

            if card_ovn['rtn'] == 0:
                for hit_card in card_ovn['results']:
                    hit_card['ip'] = H_IP
                    hit_card['ovn_f'] = hit_card['yitu_171_feature_base64']

            else:
                camera_list = yituydn.camera_list(yituydn.getcamera())
                repository_list = yituydn.repository_list(yituydn.getrepository())
                continue
            # print(cam_ovn['results'])
            # print(card_ovn['results'])
            # print('----------')
            logic(data, cam_ovn['results'], card_ovn['results'])

    except Exception as e:
        print(e)
        time.sleep(10)
        continue
